package org.rsbot.loader.asm;

public class Label
{
  static final int DEBUG = 1;
  static final int RESOLVED = 2;
  static final int RESIZED = 4;
  static final int PUSHED = 8;
  static final int TARGET = 16;
  static final int STORE = 32;
  static final int REACHABLE = 64;
  static final int JSR = 128;
  static final int RET = 256;
  static final int SUBROUTINE = 512;
  static final int VISITED = 1024;
  static final int VISITED2 = 2048;
  public Object info;
  int status;
  int line;
  int position;
  private int referenceCount;
  private int[] srcAndRefPositions;
  int inputStackTop;
  int outputStackMax;
  Frame frame;
  Label successor;
  Edge successors;
  Label next;

  public int getOffset()
  {
    if ((this.status & 0x2) == 0) {
      throw new IllegalStateException("Label offset position has not been resolved yet");
    }
    return this.position;
  }

  void put(MethodWriter paramMethodWriter, ByteVector paramByteVector, int paramInt, boolean paramBoolean)
  {
    if ((this.status & 0x2) == 0) {
      if (paramBoolean) {
        addReference(-1 - paramInt, paramByteVector.length);
        paramByteVector.putInt(-1);
      } else {
        addReference(paramInt, paramByteVector.length);
        paramByteVector.putShort(-1);
      }
    }
    else if (paramBoolean)
      paramByteVector.putInt(this.position - paramInt);
    else
      paramByteVector.putShort(this.position - paramInt);
  }

  private void addReference(int paramInt1, int paramInt2)
  {
    if (this.srcAndRefPositions == null) {
      this.srcAndRefPositions = new int[6];
    }
    if (this.referenceCount >= this.srcAndRefPositions.length) {
      int[] arrayOfInt = new int[this.srcAndRefPositions.length + 6];
      System.arraycopy(this.srcAndRefPositions, 0, arrayOfInt, 0, this.srcAndRefPositions.length);

      this.srcAndRefPositions = arrayOfInt;
    }
    this.srcAndRefPositions[(this.referenceCount++)] = paramInt1;
    this.srcAndRefPositions[(this.referenceCount++)] = paramInt2;
  }

  boolean resolve(MethodWriter paramMethodWriter, int paramInt, byte[] paramArrayOfByte)
  {
    int i = 0;
    this.status |= 2;
    this.position = paramInt;
    int j = 0;
    while (j < this.referenceCount) {
      int k = this.srcAndRefPositions[(j++)];
      int m = this.srcAndRefPositions[(j++)];
      int n;
      if (k >= 0) {
        n = paramInt - k;
        if ((n < -32768) || (n > 32767))
        {
          int i1 = paramArrayOfByte[(m - 1)] & 0xFF;
          if (i1 <= 168)
          {
            paramArrayOfByte[(m - 1)] = (byte)(i1 + 49);
          }
          else {
            paramArrayOfByte[(m - 1)] = (byte)(i1 + 20);
          }
          i = 1;
        }
        paramArrayOfByte[(m++)] = (byte)(n >>> 8);
        paramArrayOfByte[m] = (byte)n;
      } else {
        n = paramInt + k + 1;
        paramArrayOfByte[(m++)] = (byte)(n >>> 24);
        paramArrayOfByte[(m++)] = (byte)(n >>> 16);
        paramArrayOfByte[(m++)] = (byte)(n >>> 8);
        paramArrayOfByte[m] = (byte)n;
      }
    }
    return i;
  }

  Label getFirst()
  {
    return this.frame == null ? this : this.frame.owner;
  }

  boolean inSubroutine(long paramLong)
  {
    if ((this.status & 0x400) != 0) {
      return (this.srcAndRefPositions[(int)(paramLong >>> 32)] & (int)paramLong) != 0;
    }
    return false;
  }

  boolean inSameSubroutine(Label paramLabel)
  {
    if (((this.status & 0x400) == 0) || ((paramLabel.status & 0x400) == 0)) {
      return false;
    }
    for (int i = 0; i < this.srcAndRefPositions.length; i++) {
      if ((this.srcAndRefPositions[i] & paramLabel.srcAndRefPositions[i]) != 0) {
        return true;
      }
    }
    return false;
  }

  void addToSubroutine(long paramLong, int paramInt)
  {
    if ((this.status & 0x400) == 0) {
      this.status |= 1024;
      this.srcAndRefPositions = new int[(paramInt - 1) / 32 + 1];
    }
    this.srcAndRefPositions[(int)(paramLong >>> 32)] |= (int)paramLong;
  }

  void visitSubroutine(Label paramLabel, long paramLong, int paramInt)
  {
    Label localLabel1 = this;
    while (localLabel1 != null)
    {
      Label localLabel2 = localLabel1;
      localLabel1 = localLabel2.next;
      localLabel2.next = null;

      if (paramLabel != null) {
        if ((localLabel2.status & 0x800) != 0) {
          continue;
        }
        localLabel2.status |= 2048;

        if (((localLabel2.status & 0x100) != 0) && 
          (!localLabel2.inSameSubroutine(paramLabel))) {
          localEdge = new Edge();
          localEdge.info = localLabel2.inputStackTop;
          localEdge.successor = paramLabel.successors.successor;
          localEdge.next = localLabel2.successors;
          localLabel2.successors = localEdge;
        }
      }
      else
      {
        if (localLabel2.inSubroutine(paramLong))
        {
          continue;
        }
        localLabel2.addToSubroutine(paramLong, paramInt);
      }

      Edge localEdge = localLabel2.successors;
      while (localEdge != null)
      {
        if (((localLabel2.status & 0x80) == 0) || (localEdge != localLabel2.successors.next))
        {
          if (localEdge.successor.next == null) {
            localEdge.successor.next = localLabel1;
            localLabel1 = localEdge.successor;
          }
        }
        localEdge = localEdge.next;
      }
    }
  }

  public String toString()
  {
    return "L" + System.identityHashCode(this);
  }
}